package com.ithuameng.admin.exception;

import com.ithuameng.admin.app.system.model.vo.R;
import com.ithuameng.admin.enums.CommonError;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors;

/**
 * 全局异常处理器
 *
 * @author ithuameng
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

	/**
	 * 方法参数校验异常
	 * 
	 * @param e exception
	 * @return ignore
	 */
	@ExceptionHandler(ConstraintViolationException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(ConstraintViolationException e) {
		String message = e.getConstraintViolations().stream().map(cv -> cv == null ? "" : cv.getMessage())
				.collect(Collectors.joining(", "));
		log.error("错误代码{}: -> 详细信息:{},原始错误:{}", CommonError.URL_ARGUMENT_NOT_VALID, e, e.getMessage());
		return new R<>(CommonError.URL_ARGUMENT_NOT_VALID, message);
	}

	/**
	 * MethodArgumentNotValidException
	 *
	 * @param e
	 * @return
	 */
	@ExceptionHandler(MethodArgumentNotValidException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(MethodArgumentNotValidException e) {
		String errorDetail = "";
		BindingResult bindingResult = e.getBindingResult();
		if (bindingResult.hasErrors()) {
			errorDetail = bindingResult.getFieldError().getDefaultMessage();
		}
		log.error("错误代码{}: -> 详细信息:{},原始错误:{}", CommonError.METHOD_ARGUMENT_NOT_VALID, errorDetail, e.getMessage());
		return new R<>(CommonError.METHOD_ARGUMENT_NOT_VALID, errorDetail);
	}

	@ExceptionHandler(HttpRequestMethodNotSupportedException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public R<CommonError> httpRequestMethodNotSupportedException(HttpServletRequest request, HttpRequestMethodNotSupportedException e) {
		log.error("异常:" + request.getRequestURI(), e);
		log.error("错误代码{}: -> 详细信息:{},原始错误:{}", CommonError.METHOD_NOT_SUPPORT, "请求方式不正确", e.getMessage());
		return new R<>(CommonError.METHOD_NOT_SUPPORT, "请求方式不正确");
	}

	@ExceptionHandler(BindException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(BindException e) {
		String errorDetail = "";
		BindingResult bindingResult = e.getBindingResult();
		if (bindingResult.hasErrors()) {
			errorDetail = bindingResult.getFieldError().getDefaultMessage();
		}
		log.error("错误代码{}: -> 详细信息:{},原始错误:{}", CommonError.METHOD_ARGUMENT_NOT_VALID, errorDetail, e.getMessage());
		return new R<>(CommonError.METHOD_ARGUMENT_NOT_VALID, errorDetail);
	}

	@ExceptionHandler(AdminException.class)
	@ResponseStatus(HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(AdminException e) {
		log.error("错误代码{}: -> 详细信息: {} ", e.getBaseError().getValue(), e);
		return new R<>(e.getBaseError(), e.getMessage());
	}

	@ExceptionHandler(AccessDeniedException.class)
	@ResponseStatus(value = HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(AccessDeniedException e) throws Exception {
		log.error("错误代码{}: -> 详细信息: {} ", CommonError.BIZ_ERR, e);
		return new R<>(CommonError.BIZ_ERR, "无操作权限");
	}

	@ExceptionHandler(UnAnuthorizedException.class)
	@ResponseStatus(value = HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(UnAnuthorizedException e) throws Exception {
		log.error("错误代码{}: -> 详细信息: {} ", CommonError.UNAUTHORIZED, e);
		return new R<>(CommonError.UNAUTHORIZED, "用户不存在");
	}

	@ExceptionHandler(Exception.class)
	@ResponseStatus(value = HttpStatus.OK)
	@ResponseBody
	public R<CommonError> handle(Exception e) throws Exception {
		log.error("错误代码{}: -> 详细信息: {} ", CommonError.INTERNAL_SERVER_ERROR, e);
		return new R<>(CommonError.INTERNAL_SERVER_ERROR, "服务器开了点小差,请稍后再试");
	}
}
